package edu.gmu.projects.fireresponder.fusionengine;

import edu.gmu.projects.fireresponder.xml.alerts.Alert;
import edu.gmu.projects.fireresponder.xml.alerts.FirstResponderAlert;
import edu.gmu.projects.fireresponder.xml.alerts.SmokeAlarmAlert;

public class FireAnchorPoint extends AnchorPoint {

	// maximum likelihood of a single location accurately representing an event
	public static final double MAX_SINGLE_POINT_PROBABILITY = .5;
	public static final double NUMBER_OF_ALERTS_FOR_FULL_CONFIDENCE = 20;
	public static final double EXPOTENTIAL_GROWTH_RATE = .5;
	// Likelihood we will consider an alert
	public static final long OLDEST_NOTEWORTHY_ALERT = 180000; // 3 minutes

	public boolean addAlert(Alert alert) {
		boolean validAlert = false;
		
		if(alert instanceof SmokeAlarmAlert) {
			addEvent(alert);
			updatePointProbability();
			validAlert = true;
		} else if(alert instanceof FirstResponderAlert) {
			FirstResponderAlert fra = (FirstResponderAlert) alert;
			for(Alert embeddedAlert : fra.getEmbeddedAlerts()) {
				if(embeddedAlert instanceof SmokeAlarmAlert) {
					addEvent(embeddedAlert);
					setProbability(1d);
					validAlert = true;
				}
			}
		}		
		return validAlert;
	}

	public static boolean isValidAlert(Alert alert) {
		boolean validAlert = false;
		
		if(alert instanceof SmokeAlarmAlert) {
			validAlert = true;
		} else if(alert instanceof FirstResponderAlert) {
			FirstResponderAlert fra = (FirstResponderAlert) alert;
			for(Alert embeddedAlert : fra.getEmbeddedAlerts()) {
				if(embeddedAlert instanceof SmokeAlarmAlert) {
					validAlert = true;
				}
			}
		}		
		return validAlert;
	}
	
	// when a new alert comes in, we update the probability based off of the current alerts
	// and alerts in the past.  If a series of alerts has come in recently, it is probably
	// on fire.  We compare this to old probabilities, so that the probability is monotonic.
	protected void updatePointProbability() {
		if(probability >= MAX_SINGLE_POINT_PROBABILITY) {
			return; // can't get any higher
		}
		long acceptedAlertTime = System.currentTimeMillis() - OLDEST_NOTEWORTHY_ALERT;
		int validAlerts = 0;
		
		for(Event event : events) {
			if(event.timeStamp > acceptedAlertTime) {
				validAlerts++;
			} else {
				break;  // alerts are in order, most recent to oldest
			}
		}
		
		double rate = 1 / NUMBER_OF_ALERTS_FOR_FULL_CONFIDENCE;
		
		double newProbability = Math.pow(rate * ((double) validAlerts), EXPOTENTIAL_GROWTH_RATE);
		if(newProbability > MAX_SINGLE_POINT_PROBABILITY) {
			probability = MAX_SINGLE_POINT_PROBABILITY;
		} else if(newProbability > probability) {
			probability = newProbability;
		}
	}
	
}
